package com.pug.zixun.aspect.log;

import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.google.common.util.concurrent.RateLimiter;
import com.pug.zixun.commons.enums.AdminUserResultEnum;
import com.pug.zixun.commons.ex.PugBusinessException;
import com.pug.zixun.commons.utils.ip.AddressUtils;
import com.pug.zixun.commons.utils.ip.IpUtils;
import com.pug.zixun.commons.utils.ip.UserAgentUtil;
import com.pug.zixun.commons.utils.ip.Visit;
import com.pug.zixun.local.UserThreadLocal;
import com.pug.zixun.pojo.AdminLogs;
import com.pug.zixun.pojo.AdminUser;
import com.pug.zixun.service.adminlogs.IAdminLogsService;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.pug.generator.anno.PugDoc;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.sql.Blob;
import java.util.Date;
import java.util.Map;

/**
 * @author 飞哥
 * @Title: 学相伴出品
 * @Description: 飞哥B站地址：https://space.bilibili.com/490711252
 * 记得关注和三连哦！
 * @Description: 我们有一个学习网站：https://www.kuangstudy.com
 * @date 2022-07-26$ 0:06$
 */
@Component
@Slf4j
@Aspect
public class PugLogAspect {

    @Autowired
    private IAdminLogsService adminLogsService;

    @Pointcut("@annotation(com.pug.zixun.aspect.log.PugLog)")
    public void poinitCut(){

    }

    @Around("poinitCut()")
    public Object aroundAdvice(ProceedingJoinPoint proceedingJoinPoint) {
        try {
            // 前置增强
            long startTime = System.currentTimeMillis();
            // 这里执行springmvc具体的方法去了
            Object proceed = proceedingJoinPoint.proceed();
            // 后置增强
            long endtime = System.currentTimeMillis() - startTime;

            // 这里就保存日志---观察者设计模式
            MethodSignature signature = (MethodSignature) proceedingJoinPoint.getSignature();
            // 获取执行的方法
            Method method = signature.getMethod();
            // 获取方法的注解
            PugLog pugLog = method.getAnnotation(PugLog.class);
            ServletRequestAttributes requestAttributes = (ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
            HttpServletRequest request = requestAttributes.getRequest();
            HttpServletResponse response = requestAttributes.getResponse();
            AdminUser adminUser = UserThreadLocal.get();
            // 保存日志
            saveAdminLogs(endtime, method, pugLog, request,adminUser);
            return proceed;
        }catch (Throwable ex){
            throw new PugBusinessException(AdminUserResultEnum.USER_SERVER_ERROR);
        }
    }

    //限流每秒1次。如果设置为n，则每秒限流为1/n
    private RateLimiter rateLimiter= RateLimiter.create(1);

    /**
     * 保存日志
     * 附属功能
     * - 性能  --- ajax异步去处理
     * - 不要影响业务 --
     * @param endtime
     * @param method
     * @param pugLog
     * @param request
     */
    private void saveAdminLogs(long endtime, Method method, PugLog pugLog, HttpServletRequest request,AdminUser adminUser) {
        // 获取令牌
        Boolean flag = rateLimiter.tryAcquire();
        if( !flag ){
            return;
        }

        AdminLogs adminLogs = new AdminLogs();
        adminLogs.setMethodname(method.getName());
        adminLogs.setClassname(method.getDeclaringClass().getName());
        adminLogs.setRequestmethod(request.getMethod());
        adminLogs.setMethodtime(endtime);
        adminLogs.setRequesturi(request.getRequestURI());
        adminLogs.setModel(pugLog.value());
        adminLogs.setDescription(pugLog.desc());

        if(adminUser != null) {
            adminLogs.setUserId(adminUser.getId());
            adminLogs.setUsername(adminUser.getUsername());
            adminLogs.setTelephone(adminUser.getTelephone());
        }

        // 获取参数
        Parameter[] parameters = method.getParameters();
        if(parameters.length>0) {
            adminLogs.setMethodparams(parameters.toString());
        }

        // 特别要注意
        try {
            String ip = IpUtils.getIpAddr(request);
            Map<String, String> realAddressByIPForMap = AddressUtils.getRealAddressByIPForMap(ip);
            Visit userAgent = UserAgentUtil.getUserAgent(request);
            adminLogs.setProvince(realAddressByIPForMap.get("province"));
            adminLogs.setCity(realAddressByIPForMap.get("city"));
            adminLogs.setRequestip(ip);
            adminLogs.setRequestbrower(userAgent.getBrowserType());
            adminLogs.setOsversion(userAgent.getPlatformType());
        }catch (Exception ex){
            adminLogs.setProvince("");
            adminLogs.setCity("");
            adminLogs.setRequestip("未知");
            adminLogs.setRequestbrower("未知");
            adminLogs.setOsversion("未知");
        }

        adminLogsService.saveupdateAdminLogs(adminLogs);
    }

}
